package by.demchenko.sample.services.impl;

import by.demchenko.sample.dataaccess.base.AccountDao;
import by.demchenko.sample.dataaccess.base.PersonDao;
import by.demchenko.sample.dataaccess.base.ResultDao;
import by.demchenko.sample.dataaccess.base.ScheduleDao;
import by.demchenko.sample.datamodel.Account;
import by.demchenko.sample.datamodel.Course;
import by.demchenko.sample.datamodel.Person;
import by.demchenko.sample.datamodel.Schedule;
import by.demchenko.sample.datamodel.enums.ScheduleStatus;
import by.demchenko.sample.datamodel.enums.UserType;
import by.demchenko.sample.services.UserService;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.inject.Inject;
import javax.persistence.PersistenceException;
import java.util.Date;
import java.util.List;

@Service
public class UserServiceImpl implements UserService {
    private static final Logger LOGGER = LoggerFactory.getLogger(UserServiceImpl.class);

    @Inject
    private AccountDao accountDao;
    @Inject
    private PersonDao personDao;
    @Inject
    private ScheduleDao scheduleDao;
    @Inject
    private ResultDao resultDao;


    @Override
    public void createNewUser(Person person, Account account) {
        Validate.isTrue(person.getId() == null, "This method should be called for 'not saved yet' person only. Use UPDATE instead");

        // Check if there is no account with the same fields in DB
        if (accountDao.getAccountByCredentials(account.getLogin(), account.getPassword()) == null) {
            person.setAccount(account);
            personDao.insert(person);
        }
        else {
            throw new PersistenceException("Account already exists!");
        }
    }

    @Override
    public void removeUser(Integer id) {
        personDao.delete(id);
        accountDao.delete(id);
    }

    @Override
    public void save(Person person) {
        personDao.insert(person);
    }

    @Override
    public void saveOrUpdate(Person person) {
        if (person.getId() == null) {
            //LOGGER.debug("Save new: {}", person);
            personDao.insert(person);
        } else {
            //LOGGER.debug("Update: {}", person);
            personDao.update(person);
        }
    }

    @Override
    public Person get(Integer id) {
        return personDao.getById(id);
    }

    @Override
    public Person get(Integer id, boolean fetchJoins) {
        return personDao.getById(id, fetchJoins);
    }

    @Override
    public List<Person> findAll() {
        return personDao.findAll();
    }

    public boolean enrollInCourse(Person student, Course course, Date date) {
        if (student.getAccount().getUserType() != UserType.STUDENT) {
            LOGGER.debug(student.getFullName() + " is not a student!");
            return false;
        }

        Schedule scheduleRecord = scheduleDao.findRecord(course, date);

        if (scheduleRecord == null) {
            LOGGER.debug("Record in schedule is not found!");
            return false;
        }

        if (scheduleRecord.getStatus() != ScheduleStatus.OPENED) {
            LOGGER.debug("Schedule record is not opened!");
            return false;
        }

        List<Schedule> currentRegistration = student.getSchedules();
        if (!currentRegistration.contains(scheduleRecord)) {
            currentRegistration.add(scheduleRecord);
            student.setCourseSchedules(currentRegistration);
            saveOrUpdate(student);
            scheduleRecord.setRegistered(scheduleRecord.getRegistered() + 1);
            if (scheduleRecord.getRegistered() == scheduleRecord.getTotal()) {
                scheduleRecord.setStatus(ScheduleStatus.CLOSED);
                scheduleDao.update(scheduleRecord);
                scheduleRecord = scheduleDao.findRecord(course, date);
                resultDao.createTable(scheduleRecord);
            } else {
                scheduleDao.update(scheduleRecord);
            }
        } else {
            return false;
        }

        return true;
    }

    @Override
    public Account getAccountByCredentials(String userName, String password) {
        return accountDao.getAccountByCredentials(userName, password);
    }

    @Override
    public boolean isEnrolledInCourse(Person user, Course course, Date startDate) {
        return personDao.isEnrolledInCourse(user, course, startDate);
    }

    @Override
    public boolean cancelCourse(Person student, Schedule schedule) {
        if (schedule.getStatus() != ScheduleStatus.OPENED) {
            LOGGER.debug("Schedule record is not opened!");
            return false;
        }
        List<Schedule> currentRegistration = student.getSchedules();
        currentRegistration.remove(schedule);
        student.setCourseSchedules(currentRegistration);
        saveOrUpdate(student);

        schedule.setRegistered(schedule.getRegistered() - 1);
        scheduleDao.update(schedule);

        return true;
    }

}
